/**
 * DESCRIPTION:CGI COMMON HEAD FILE
 *  UPDATETIME:2013.10.8/2013.11.12/2013.11.27/2014.03.29
 *   DEVELOPER:
 * REVISETIMES:1/2/3/4/5
 *  CREATETIME:2013.7.30
 */

#ifndef _CGI_H_
#define _CGI_H_

#include <string>
#include <iostream>
#include <map>
#include <vector>
#include <cstdio>
#include <fstream>
#include <sstream>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <errno.h>
#ifdef __posix
#include <regex.h>
#endif

/* uint32_t */
#include <stdint.h>
#include <sys/time.h>
#include <assert.h>
#include <fcntl.h>

using namespace std;

#ifndef RELEASE_VERSION
#define RELEASE_VERSION "140311"
#endif

#define SYSTEM_TEMP_PATH "/tmp/"

#ifndef __posix
    #define CGILOGFILE "cppcgi.log"
#else
    #define CGILOGFILE SYSTEM_TEMP_PATH"/cppcgi.log"
#endif

namespace cppcgi
{

#define CLOG(risk) COMPACT_WEB_LOG_ ## risk

#define COMPACT_WEB_LOG_SYSTEM LogMessage("S ") \
            .Stream()

#define COMPACT_WEB_LOG_INFO LogMessage("I ", \
            __FUNCTION__, __LINE__).Stream()

#define COMPACT_WEB_LOG_ERROR LogMessage("E ", \
            __FUNCTION__, __LINE__).Stream()

#define MAX_LINE_LENGTH 128
#define LINE_LENGTH_64 64
#define LINE_LENGTH_32 32
#define LINE_LENGTH_16 16
#define MIN_LINE_LENGTH 8

#define MAX_UPLOAD_LENGTH 200000000 //max 200M

#define REGEX_SUBSTRING_SIZE 10

#if 0

#define CGIOUT cout
#define CGIOUTS stdout
#define CGILOG(INFO) CGIOUT << "<p>" << GetFormatTime() << " " \
            << __FUNCTION__ << ":" << __LINE__ << "</p>" << endl
#define CGICS CGIOUT << "<p>---"
#define CGICE "---</p>" << endl
#define CGICC CGIOUT << "<p>______</p>" << endl
#define CGIENTER "<br />"
#define CGIBLANK "&nbsp;"

#else

#define CGIOUT cerr
#define CGIOUTS stderr
#define CGILOG(INFO) CGIOUT << GetFormatTime() << " " \
            << __FUNCTION__ << ":" << __LINE__ << endl
#define CGICS CGIOUT << "---"
#define CGICE "---" << endl
#define CGICC CGIOUT << "______" << endl
#define CGIENTER "\n"
#define CGIBLANK " "

#endif

typedef map<string, string> kvmap;
typedef map<string, kvmap> mkvmap;

struct rkv
{
    string key;
    string value;
};

struct rfile
{
    char* key;
    char* name;
    char* type;
    char* data;
    unsigned int size;
};

typedef vector<struct rkv> kvvector;
typedef vector<struct rfile> filevector;

class KvVector
{
public:
    KvVector();
    KvVector(kvvector& prop);
    string GetKey(int index);
    string GetValue(int index);
    string GetValue(const string& key);
    int Size();
    bool Empty();
    void Clear();
    int Exist(const string& key);
    bool Insert(const string& key, const string& value);
    bool SetValue(const string& key, const string& value);
    bool SetKey(int index, const string& key);
    bool SetValue(int index, const string& value);
    bool Erase(const string& key);
    bool Erase(int index);
    string operator[](int);
    string operator[](const string& key);

    static KvVector Split(const string str, const string delim);
    static KvVector StrSplit(const string& context,
        const string& str_delim,
        const string& kv_delim);

    static KvVector UrlSplit(const string& context);

private:
    kvvector data_;
};

class KvMap
{
public:
    KvMap();
    KvMap(kvmap& prop);
    string GetKey(int index);
    string GetValue(int index);
    string GetValue(const string& key);
    int Size();
    bool Empty();
    void Clear();
    bool Exist(const string& key);
    bool Insert(const string& key, const string& value);
    bool Erase(const string& key);
    void ForConfig();
    void ForGeneral();
    kvmap Dump();
    string operator[](const string& key);

    static KvMap StrSplit(const string& context,
        const string& str_delim,
        const string& kv_delim);
private:
    bool isConfig_;
    kvmap data_;
};

class FileVector
{
public:
    FileVector();
    FileVector(filevector& prop);
    int Size();
    bool Insert(struct rfile& file);
    bool Erase(const string& key);
    struct rfile operator[](int index);
    struct rfile operator[](const string& key);

private:
    filevector data_;
};

class CppCgi
{
public:
    CppCgi();
    ~CppCgi();

    void Test();

    KvVector post;
    KvVector get;
    KvMap server;
    FileVector file;
    KvMap cookie;

private:
    static bool isCppCgiInited;
};

class Cookie
{
    string cookieStr_;
    KvMap cookieMap_;

public:
    Cookie();
    ~Cookie();

    static KvMap Get();
    static void Set(const string& name, const string& value, const string& extra);
    void Add(const string& name, const string& value);
    void Out();

};

class File
{
    FILE* pstream_;
private:
    File(FILE* stream);

public:
    File();
    File(const string& fileName);
    ~File();
    static File* Open(const string& fileName, const string& mode);
    bool IsEmpty();
    bool GetLine(string&);
    void AddLine(const string&);
    void Write(const string& context);
    void Save();
};

typedef map<string, KvMap> mKvMap;
/**
 *
 */
class ConfigSet
{
    KvMap ppair_;
    mKvMap pgroup_;
    File* file_;
    string fileName_;
    bool fileExist_;
private:
    int LoadFromFile(const string&);

public:
    ConfigSet();

    ConfigSet(const string& fileName);

    ~ConfigSet();
    // xu yao shou dong save
    void Insert(const string&, const string&);
    void Insert(KvMap&);
    void MInsert(const string&, KvMap&);
    void MInsert(const string&, const string&, const string&);
    void MDelet(const string&);
    bool Empty();
    bool Clear();
    int Size();
    string GetKey(int index);
    KvMap GetKv();
    void Test();
    void Save();
    int SaveToFile(const string& fileName);
    KvMap operator[](const string&);

    static ConfigSet ConfigSetSplit(KvVector& input, const string& keyDelim);
};

typedef map<string, KvVector> kVectorMap;
/**
 *
 */
class OrderedConfigSet
{
    KvVector ppair_;
    kVectorMap pgroup_;
    File* file_;
    string fileName_;
    bool fileExist_;
private:
    int LoadFromFile(const string&);

public:
    OrderedConfigSet();

    OrderedConfigSet(const string& fileName);

    ~OrderedConfigSet();
    // xu yao shou dong save
    void Insert(const string&, const string&);
    void Insert(KvVector&);
    void MInsert(const string&, KvVector&);
    void MInsert(const string&, const string&, const string&);
    void MDelet(const string&);
    bool Empty();
    bool Clear();
    int Size();
    string GetKey(int index);
    KvVector GetKv();
    void Test();
    void Save();
    int SaveToFile(const string& fileName);
    KvVector operator[](const string&);
};

/**
 *
 */
class Test
{
public:
    static void Alert(const string& str);
    static void Alert(kvmap& prop);
    static void Alert(KvMap& prop);
    static void Alert(KvVector& prop);
    static void Show(const char* str, int len, const char* format);
};

class LogMessage
{
public:
    LogMessage(const char* mask);
    LogMessage(const char* mask, int id);
    LogMessage(const char* mask, const char* file, int line);
    ~LogMessage();
    ofstream& Stream();
private:
    ofstream fileobj_;
};

class CIntStr
{
public:
    CIntStr(int num);
    CIntStr(uint32_t num, bool);
    CIntStr(const string num);

    string ToString();

    int ToInt();
    uint32_t ToUint();

private:
    string num_;
};

#ifdef __posix
class CRegex
{
private:
    regex_t regexObj_;
    size_t nmatch_;
    regmatch_t* pmatch_;
    string errmsg_;
    string objstring_;
public:
    CRegex(const string& regexSrc);

    ~CRegex();

    bool Match(const string& str);

    string GetMatchStr(int);
};
#endif

#ifndef __notcgi

#define X(sHtml) printf("%s", #sHtml);

extern CppCgi cppcgi_global;

#define $_POST cppcgi_global.post
#define $_GET cppcgi_global.get
#define $_FILE cppcgi_global.file
#define $_SERVER cppcgi_global.server
#define $_COOKIE cppcgi_global.cookie

#endif

extern int error_code;

string SimplePath(const string& str);

void InitFunc(const string& str);
/**
 *
 */
string GetEnv(const string& param);
/**
 *
 */
string ToUpperCase(const string& s);
/**
 *
 */
string ToLowCase(const string& s);
/**
 *
 */
string ToProperCase(const string& s);
/**
 *
 */
string GetFormatTime();
/**
 *
 */
void ReplaceStr(string& str,
    const string& searchString,
    const string& replaceString);
/**
 * shan chu zi fu chuan liang bian de kong ge
 */
void Trim(string& s);
/**
 *
 */
void Head();
/**
 *
 */
void Head(const string& type);
/**
 *
 */
char* CharSplit(char* s, const char* delim, char** lasts);

/**
 *
 */
string DecodeUrlComponent(const string& value);
/**
 *
 */
unsigned int HexChar2Int(const char* s);

/**
 *
 */
void CopyChar(char*& dst, const char* src, int len);
/**
 *
 */
int FindMatch(const char* buf, const char* src);
/**
 *
 */
int FindMatchAll(const char* buf, const char* src, int maxoffset);
/**
 *
 */
int SaveToFile(const char* buf, const char* file, int length);
/**
 *
 */
string CheckFirst(bool& tag, const string& s);
/**
 *
 */
string PreJsonStr(string& str);
/**
 *
 */
bool PropToJson(KvMap& prop, string& json);
bool PropToJson(KvVector& prop, string& json);
/**
 *
 */
bool MultiPropToJson(mkvmap&, string&);
/**
 *
 */
int GetStrChar(char** lineptr,
    size_t* n,
    FILE* stream,
    char terminator,
    int offset);
/**
 *
 */
int GetLineChar(char** lineptr,
    size_t* n,
    FILE* stream);

int ReadNoblock(FILE *fp, char *buf, int size, int ms);

void Print(const string str);

}   //namespace cppcgi
#endif
